﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace JGSY.Tasks
{
    public class CancellationToken1
    {
        public static async Task CancellationToken001()
        {
            // 1. 创建 CancellationTokenSource（核心属性：Token, IsCancellationRequested）
            var cts = new CancellationTokenSource();
            CancellationToken token = cts.Token;
            // 作用：创建一个取消令牌源，用于生成取消令牌（Token）和控制取消行为。
            // Token 是传递给异步操作的取消信号，IsCancellationRequested 表示是否已请求取消。

            // 2. 注册取消回调（方法：Register）
            token.Register(() => Console.WriteLine("\n取消请求已触发！"));
            // 作用：当取消被触发时（调用 cts.Cancel()），此回调会执行，输出提示信息。

            // 3. 启动多个异步操作
            var task1 = LongRunningOperationAsync(token, "任务A");
            var task2 = LongRunningOperationAsync(token, "任务B");
            var task3 = Task.Run(() => CountdownWithTimeout(cts));
            // 作用：启动三个并行任务：
            // - task1/task2：执行长时间循环操作，支持取消检查。
            // - task3：在后台线程中运行 CountdownWithTimeout，负责触发超时取消。

            // 4. 等待任意任务完成或取消
            try
            {
                await Task.WhenAny(task1, task2, task3);
                // 作用：等待 task1/task2/task3 中任意一个完成（无论成功、失败或取消）。

                cts.Cancel(); // 触发协作式取消（方法：Cancel）
                              // 作用：主动请求取消所有关联此 Token 的异步操作。
                              // 注意：此时 task1/task2 可能仍在运行，需等待它们响应取消。

                await Task.WhenAll(task1, task2); // 确保所有任务完成
                                                  // 作用：等待 task1 和 task2 进入最终状态（完成/取消/异常）。
                                                  // 意义：确保资源释放和状态一致性，即使任务未立即响应取消。
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("\n操作已取消");
            }
            catch (AggregateException ae)
            {
                Console.WriteLine($"\n捕获到异常: {ae.Flatten().InnerException?.Message}");
            }
        }

        // 长时间运行操作（包含所有关键方法）
        static async Task LongRunningOperationAsync(CancellationToken token, string taskName)
        {
            try
            {
                for (int i = 0; i < 5; i++)
                {
                    // 5. 检查取消请求（属性：IsCancellationRequested）
                    token.ThrowIfCancellationRequested(); // 方法：ThrowIfCancellationRequested
                                                          // 作用：如果 Token 已收到取消请求，抛出 OperationCanceledException。
                                                          // 关键点：任务必须主动调用此方法才能响应取消。

                    Console.WriteLine($"{taskName} 进度: {i * 20}%");
                    await Task.Delay(1000, token); // 支持取消的延迟
                                                   // 作用：延迟 1 秒，同时监听取消信号。如果取消，延迟会提前终止。
                }
                Console.WriteLine($"{taskName} 完成");
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine($"{taskName} 被取消");
                throw; // 重新抛出以在 WhenAll 中捕获
            }
        }

        // 带超时的倒计时控制
        static void CountdownWithTimeout(CancellationTokenSource cts)
        {
            // 6. 设置 3 秒后自动取消（方法：CancelAfter）
            cts.CancelAfter(3000);
            // 作用：3 秒后自动触发 cts.Cancel()，无需手动调用。

            // 7. 使用 WaitHandle 监听取消（属性：WaitHandle）
            cts.Token.WaitHandle.WaitOne();
            // 作用：阻塞当前线程，直到收到取消信号（通过 cts.Cancel() 或 CancelAfter）。
            // 关键点：WaitOne() 会一直等待，直到 Token 被取消。

            Console.WriteLine("\n超时触发取消");
        }
    }
}
